﻿using System;
using System.Collections.Generic;
using GGEditor.API.Utility.Algorithms;
using System.Reflection;

namespace GGEditor.API.Utility
{
    public class ExceptionFormatter
    {
        private class CategoryFormatter
        {
            private string category;
            private object data;
            private string separator = " ";
            private int columnWidth = 18;
            
            public string Category
            {
                get { return category; }
                set { category = value; }
            }

            public object Data
            {
                get { return data; }
                set { data = value; }
            }

            public string Separator
            {
                get { return separator; }
                set { separator = value; }
            }

            public override string ToString()
            {
                string fmt = (columnWidth > 0) ? "{0,-"+columnWidth.ToString()+"}{1}{2}" : "{0}:{1}{2}";
                return string.Format(fmt, category + ":", separator, data);
            }
        }

        #region ExceptionFormatter Members

        private readonly Exception e;
        private readonly List<object> formatters = new List<object>();
        private string separator = "\r\n";
        private int indent = 0;
        private readonly DateTime raisedTime;

        public ExceptionFormatter(Exception e) : this(e, DateTime.Now) { }

        public ExceptionFormatter(Exception e, DateTime raisedTime)
        {
            this.e = e;
            this.raisedTime = raisedTime;

            if (e.GetType() == typeof(TargetInvocationException))
                e = e.InnerException;
            formatters.Add("EXCEPTION REPORT\r\n");
            formatters.Add(new CategoryFormatter() {
                Category = "Time",
                Data = raisedTime
            });
            formatters.Add(new CategoryFormatter() {
                Category = "Message",
                Data = e.Message
            });
            formatters.Add(new CategoryFormatter() {
                Category = "Exception",
                Data = e.GetType().FullName
            });
            formatters.Add(new CategoryFormatter() {
                Category = "Stack Trace",
                Data = "\r\n" + e.StackTrace
            });
            formatters.Add("\r\n\r\n");
            if (e.InnerException != null)
                formatters.Add(new ExceptionFormatter(e.InnerException, raisedTime) {
                                                                            Indent = indent + 1,
                                                                            Separator = separator,
                                                                        });
        }

        public string Separator
        {
            get { return separator; }
            set { separator = value; }
        }

        public int Indent
        {
            get { return indent; }
            set { indent = value; }
        }

        public override string ToString()
        {
            string[] list = Map.ToArray<object, string>(
                formatters.ToArray(), delegate(object o) {
                                return o.ToString();
                            });
            string unindented = string.Join(Separator, list);
            return unindented;
        }

        #endregion
    }
}
